
using System;
using System.Net;
using System.Xml;
using System.IO;
using System.Collections;
using System.ServiceModel.Syndication;
using System.Collections.Generic;
using System.Threading;

namespace HTTPConnector
{
    internal interface ISubscriber
    {
        void OnNewFeed(SyndicationFeed feed);
    }

    internal class Channel
    {
        public Channel(ISubscriber Subscriber)
        {
            m_Status = false;
            m_Subscriber = Subscriber;
        }
        public bool m_Status;
        public ISubscriber m_Subscriber;
    }

    public class Advisor : IDisposable
    {
        private WebClient                   m_HTTPServerNotificationRequest;
        private string                      m_ServerName;
        private string                      m_Cookie;
        private Dictionary<string, Channel> m_Channels = new Dictionary<string, Channel>();
        private bool                        m_Disposed = false;
        
        /// <summary>
        /// Classe per la gestione delle richieste e notifiche del server
        /// </summary>
        public Advisor(string ServerName)
        {
            m_ServerName = ServerName;

            m_HTTPServerNotificationRequest = new WebClient();
            m_HTTPServerNotificationRequest.DownloadStringCompleted += new DownloadStringCompletedEventHandler(HTTPServerNotificationRequest_DownloadStringCompleted);
            m_HTTPServerNotificationRequest.DownloadStringAsync(new Uri("http://" + m_ServerName + "/advice"));
        }

        #region Server callback

        private void _SubscribeChannel(string ChannelName, ISubscriber Subscriber)
        {
            if (m_Cookie != null)
            {
                WebClient Request = new WebClient();
                Request.DownloadStringCompleted += (object sender, DownloadStringCompletedEventArgs e) =>
                {
                    if (m_Disposed == true)
                        return;
                    if (e.Error != null)
                    {
                        Request.DownloadStringAsync(new Uri("http://" + m_ServerName + "/advice/" + ChannelName + "/" + m_Cookie));
                        return;
                    }
                    m_Channels[ChannelName].m_Status = true;
                };
                Request.DownloadStringAsync(new Uri("http://" + m_ServerName + "/advice/" + ChannelName + "/" + m_Cookie));
            }
        }

        internal void SubscribeChannel(string ChannelName, ISubscriber Channel)
        {
            m_Channels[ChannelName] = new Channel(Channel);
            _SubscribeChannel(ChannelName, Channel);
        }

        private void HTTPServerNotificationRequest_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (m_Disposed == true)
                return;

            if (e.Error != null)
            {
                // Log error
                if (m_Cookie != null)
                    m_HTTPServerNotificationRequest.DownloadStringAsync(new Uri("http://" + m_ServerName + "/advice/" + m_Cookie));
                else
                    m_HTTPServerNotificationRequest.DownloadStringAsync(new Uri("http://" + m_ServerName + "/advice"));
                return;
            }

            SyndicationFeed feed;
            try
            {
                feed = SyndicationFeed.Load(XmlReader.Create(new StringReader(e.Result)));
            }
            catch (Exception b)
            {
                // Log error
                if (m_Cookie != null)
                    m_HTTPServerNotificationRequest.DownloadStringAsync(new Uri("http://" + m_ServerName + "/advice/" + m_Cookie));
                else
                    m_HTTPServerNotificationRequest.DownloadStringAsync(new Uri("http://" + m_ServerName + "/advice"));
                return;
            }

            string Category = feed.Categories[0].Name;
            if (Category == "advice")
            {
                m_Cookie = feed.Id;

                foreach (string n in m_Channels.Keys)
                {
                    Channel MyChannel = m_Channels[n];
                    if (MyChannel.m_Status == false)
                    {
                        _SubscribeChannel(n, MyChannel.m_Subscriber);
                    }
                }

                m_HTTPServerNotificationRequest.DownloadStringAsync(new Uri("http://" + m_ServerName + "/advice/" + m_Cookie));
                return;
            }

            if (m_Channels.ContainsKey(Category) == false)
            {
                // Log error
                m_HTTPServerNotificationRequest.DownloadStringAsync(new Uri("http://" + m_ServerName + "/advice/" + m_Cookie));
                return;
            }

            if (m_Channels[Category].m_Status == true)
            {
                m_Channels[Category].m_Subscriber.OnNewFeed(feed);
            }

            m_HTTPServerNotificationRequest.DownloadStringAsync(new Uri("http://" + m_ServerName + "/advice/" + m_Cookie));
        }

        #endregion

#region Direct Call To Server

        public void SendGet(string UriPart)
        {
            WebClient Request = new WebClient();
            Request.DownloadStringCompleted += (object sender, DownloadStringCompletedEventArgs e) =>
            {
                if (m_Disposed == true)
                    return;
                if (e.Error != null)
                {
                    Request.DownloadStringAsync(new Uri("http://" + m_ServerName + "/" + UriPart));
                    return;
                }
                SyndicationFeed feed;
                try
                {
                    feed = SyndicationFeed.Load(XmlReader.Create(new StringReader(e.Result)));
                }
                catch (Exception b)
                {
                    Request.DownloadStringAsync(new Uri("http://" + m_ServerName + "/" + UriPart));
                    return;
                }
                string Category = feed.Categories[0].Name;
                if (m_Channels.ContainsKey(Category) == false)
                {
                    Request.DownloadStringAsync(new Uri("http://" + m_ServerName + "/" + UriPart));
                    return;
                }
                if (m_Channels[Category].m_Status == true)
                {
                    m_Channels[Category].m_Subscriber.OnNewFeed(feed);
                }
            };
            Request.DownloadStringAsync(new Uri("http://" + m_ServerName + "/" + UriPart));
        }

 #endregion

#region IDisposable Membri di

        private void Dispose(bool disposing)
        {
            try
            {
                if (!m_Disposed)
                {
                    if (disposing)
                    {
                        if (m_HTTPServerNotificationRequest != null)
                            m_HTTPServerNotificationRequest.CancelAsync();
                    }
                }
            }
            finally
            {
                m_Disposed = true;
            }
        }
        /// <summary>
        /// Libera la memoria
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
        }

#endregion
    }
}


